#pragma once
#include <d3dx9.h>

template <typename T>
class Vector3
{
public:
	T x, y, z;
public:
	Vector3(void);
	Vector3(T inx, T iny, T inz=(T)0);
	~Vector3(void);
	
public:
	operator Vector3<float>(){return (Vector3<float>((float)x,(float)y,(float)z));}
	operator D3DXVECTOR3(){return (D3DXVECTOR3(x,y,z));}
	Vector3<T>& operator=(const Vector3<T>& other);

	Vector3<T> operator+(Vector3<T>& other);
	void operator+=(Vector3<T>& other);

	Vector3<T> operator-(Vector3<T>& other);
	void operator-=(Vector3<T>& other);
	Vector3<T> operator-();

	Vector3<T> operator*(T other);
	void operator*=(T other);
	
	float operator*(Vector3<T> other);

	bool operator==(Vector3<T> other);

	float Norm();
	float NormSquar();
	Vector3<T> Normalize();
};
typedef Vector3<float> Vector3f;
typedef Vector3<long> Vector3l;
typedef Vector3<int> Vector3i;



template <typename T>
Vector3<T>::Vector3(void)
	:x(0), y(0), z(0)
{
}

template <typename T>
Vector3<T>::Vector3(T inx,T iny,T inz)
	:x(inx), y(iny), z(inz)
{
}


template <typename T>
Vector3<T>::~Vector3(void)
{
}

// =
template <typename T>
Vector3<T>& Vector3<T>::operator=(const Vector3<T>& other)
{
	x=other.x, y=other.y, z=other.z;
	return (*this);
}

// +
template <typename T>
Vector3<T> Vector3<T>::operator+(Vector3<T>& other)
{
	return Vector3<T>(x+other.x, y+other.y, z+other.z);
}

template <typename T>
void Vector3<T>::operator+=(Vector3<T>& other)
{
	x+=other.x, y+=other.y, z+=other.z;
}

// -
template <typename T>
Vector3<T> Vector3<T>::operator-(Vector3<T>& other)
{
	return Vector3<T>(x-other.x, y-other.y, z-other.z);
}

template <typename T>
void Vector3<T>::operator-=(Vector3<T>& other)
{
	x-=other.x, y-=other.y, z-=other.z;
}

template <typename T>
Vector3<T> Vector3<T>::operator-()
{
	return Vector3<T>(-x, -y, -z);
}

// *
template <typename T>
Vector3<T> Vector3<T>::operator*(T other)
{
	return Vector3<T>(x*other, y*other, z*other);
}

template <typename T>
void Vector3<T>::operator*=(T other)
{
	x*=other.x, y*=other.y, z*=other.z;
}

template <typename T>
float Vector3<T>::operator*(Vector3<T> other)
{
	return (x*other.x + y*other.y + z*other.z);
}

template <typename T>
float Vector3<T>::Norm()
{
	return (sqrtf((float)(x*x + y*y + z*z)));
}

template <typename T>
float Vector3<T>::NormSquar()
{
	return (float)(x*x + y*y + z*z);
}

template <typename T>
Vector3<T> Vector3<T>::Normalize()
{
	Vector3<T> result;
	float norm = this->Norm();
	if( norm >= 0.000001f )
	{
		result.x = (T)(x/norm);
		result.y = (T)(y/norm);
		result.z = (T)(z/norm);
	}
	return result;
}

template <typename T>
bool Vector3<T>::operator==(Vector3<T> other)
{
	return (x==other.x && y==other.y && z==other.z);
}
